package sip_core

import (
	"fmt"
	"math/rand"
	"strings"
	"time"
)

type PlayType string

const (
	REAL_PLAY      PlayType = "Play"
	PLAY_BACK      PlayType = "Playback"
	PLAY_BACK_DOWN PlayType = "Download"
	AUDIO_TALK     PlayType = "Talk"
)

type SDPbody struct {
	SipSvrID            string
	SipSvrIP            string
	MediaServerIP       string
	PushMediaStreamPort string
	PlayType            PlayType
	StartTime           string
	EndTime             string
	PlayingDeviceID     string
	ChannelID           string
	SSRC                string
	IsAudio             bool
	DownSpeed           string
	Fbody               string
	IsTCP               bool
}

func (builder *SDPbody) VideoPlayString() string {
	if builder.SSRC == "" {
		builder.MakeSSRC()
	}

	sdpStr := "v=0\r\n"
	sdpStr += fmt.Sprintf("o=%s 0 0 IN IP4 %s\r\n", builder.SipSvrID, builder.MediaServerIP)
	sdpStr += fmt.Sprintf("s=%s\r\n", builder.PlayType)
	if builder.PlayType == PLAY_BACK || builder.PlayType == PLAY_BACK_DOWN {
		sdpStr += fmt.Sprintf("u=%s:%s\r\n", builder.PlayingDeviceID, "0")
	}
	sdpStr += fmt.Sprintf("c=IN IP4 %s\r\n", builder.MediaServerIP)
	sdpStr += fmt.Sprintf("t=%s %s\r\n", builder.StartTime, builder.EndTime)
	sdpStr += fmt.Sprintf("m=video %s RTP/AVP 96 98 97\r\n", builder.PushMediaStreamPort)
	sdpStr += "a=recvonly\r\n"
	sdpStr += "a=rtpmap:96 PS/90000\r\n"
	sdpStr += "a=rtpmap:98 H264/90000\r\n"
	sdpStr += "a=rtpmap:97 MPEG4/90000\r\n"
	if builder.PlayType == PLAY_BACK_DOWN {
		sdpStr += fmt.Sprintf("a=downloadspeed:%s\r\n", builder.DownSpeed)
		// sdpStr += "a=downloadspeed:4\n"
	}
	// sdpStr += "a=streamprofile:0\r\n"
	// sdpStr += "a=streamnumber:0\r\n"
	sdpStr += fmt.Sprintf("y=%s\r\n", builder.SSRC)

	return sdpStr
}

// 生成sdp消息
func (builder *SDPbody) StringOld() string {
	if builder.SSRC == "" {
		builder.MakeSSRC()
	}
	var tempStr string
	if builder.PlayType == PLAY_BACK || builder.PlayType == PLAY_BACK_DOWN {
		tempStr = fmt.Sprintf("u=%s:%s\r\n", builder.PlayingDeviceID, builder.ChannelID)
	}

	sdpStr := fmt.Sprintf("v=0\r\no=%s 0 0 IN IP4 %s\r\ns=%s\r\n%sc=IN IP4 %s\r\nt=%s %s\r\n",
		builder.SipSvrID, builder.MediaServerIP, builder.PlayType, tempStr, builder.MediaServerIP, builder.StartTime, builder.EndTime)

	if builder.IsAudio {
		//audio
		if builder.IsTCP {
			sdpStr += fmt.Sprintf("m=audio %s TCP/RTP/AVP 8\r\n", builder.PushMediaStreamPort)
		} else {
			sdpStr += fmt.Sprintf("m=audio %s RTP/AVP 8\r\n", builder.PushMediaStreamPort)
		}

		sdpStr += "a=sendonly\r\na=rtpmap:8 PCMA/8000\r\n"

		// sdpStr += fmt.Sprintf("m=audio %s RTP/AVP 96\n", builder.PushMediaStreamPort)
		// sdpStr += "a=sendonly\na=rtpmap:96 PS/90000\n"
		// sdpStr += "a=streamprofile:0\n"
		// sdpStr += "a=streamnumber:0\n"

	} else {
		//video
		if builder.IsTCP {
			sdpStr += fmt.Sprintf("m=video %s TCP/RTP/AVP 96 98 97\r\n", builder.PushMediaStreamPort)
		} else {
			sdpStr += fmt.Sprintf("m=video %s RTP/AVP 96 98 97\r\n", builder.PushMediaStreamPort)
		}
		sdpStr += "a=recvonly\r\n"
		if builder.IsTCP {
			sdpStr += "a=setup:passive\r\n"
			sdpStr += "a=connection:new\r\n"
		}
		sdpStr += "a=rtpmap:96 PS/90000\r\na=rtpmap:98 H264/90000\r\na=rtpmap:97 MPEG4/90000\r\n"
	}

	// sdpStr += "a=setup:passive\na=connection:new\n"
	if builder.PlayType == PLAY_BACK_DOWN {
		sdpStr += fmt.Sprintf("a=downloadspeed:%s\r\n", builder.DownSpeed)
		// sdpStr += "a=downloadspeed:4\n"
	}

	sdpStr += fmt.Sprintf("y=%s\r\n", builder.SSRC)
	if builder.IsAudio {
		if builder.Fbody != "" {
			sdpStr += "f=" + builder.Fbody
		} else {
			sdpStr += "f=v/////a/1/8/1"
		}
	}
	sdpStr += "\r\n"
	return sdpStr
}

func (builder *SDPbody) MakeSSRC() string {
	ssrcStr := "0"
	if builder.PlayType != REAL_PLAY {
		ssrcStr = "1"
	}
	if len(builder.SipSvrID) == 20 {
		sid := builder.SipSvrID[3:8]
		ssrcStr += sid + RandomString(4)
		builder.SSRC = ssrcStr
	}

	return ssrcStr
}

func ParseSdpMessage(sdpStr string) *SDPbody {
	list := strings.Split(strings.ReplaceAll(sdpStr, "\r\n", "\n"), "\n")

	var sipSvrID, sipSvrIP, ssrc, mediaServerIP, pushMediaStreamPort, playType, deviceID, channelID, fbody string
	startTime := "0"
	endTime := "0"
	isAudio := false

	for _, e := range list {
		parts := strings.Split(e, "=")

		if len(parts) > 1 && strings.TrimSpace(parts[0]) == "o" {
			partsChilds := strings.Split(parts[1], " ")
			if len(partsChilds) > 5 {
				sipSvrID = strings.TrimSpace(partsChilds[0])
				sipSvrIP = strings.TrimSpace(partsChilds[5])
			}
		}

		if len(parts) > 1 && strings.TrimSpace(parts[0]) == "s" {
			playType = parts[1]
		}

		if len(parts) > 1 && strings.TrimSpace(parts[0]) == "u" {
			partsChilds := strings.Split(parts[1], ":")
			if len(partsChilds) > 1 {
				deviceID = strings.TrimSpace(partsChilds[0])
				channelID = strings.TrimSpace(partsChilds[1])
			}
		}

		if len(parts) > 1 && strings.TrimSpace(parts[0]) == "c" {
			//parts[1]=IN IP4 172.20.16.3
			partsChilds := strings.Split(parts[1], " ")
			if len(partsChilds) > 2 {
				mediaServerIP = strings.TrimSpace(partsChilds[2])
			}
		}

		if len(parts) > 1 && strings.TrimSpace(parts[0]) == "t" {
			partsChilds := strings.Split(parts[1], " ")
			if len(partsChilds) > 1 {
				startTime = strings.TrimSpace(partsChilds[0])
				endTime = strings.TrimSpace(partsChilds[1])
			}
		}

		if len(parts) > 1 && strings.TrimSpace(parts[0]) == "m" {
			//parts[1]=audio 8000 RTP/AVP 8
			partsChilds := strings.Split(parts[1], " ")
			if len(partsChilds) > 2 {
				pushMediaStreamPort = strings.TrimSpace(partsChilds[1])
				if partsChilds[0] == "audio" {
					isAudio = true
				}
			}
		}

		if len(parts) > 1 && strings.TrimSpace(parts[0]) == "y" {
			ssrc = parts[1]
		}

		if len(parts) > 1 && strings.TrimSpace(parts[0]) == "f" {
			fbody = parts[1]
		}
	}
	return &SDPbody{
		SipSvrID:            sipSvrID,
		SipSvrIP:            sipSvrIP,
		MediaServerIP:       mediaServerIP,
		PushMediaStreamPort: pushMediaStreamPort,
		PlayType:            PlayType(playType),
		StartTime:           startTime,
		EndTime:             endTime,
		PlayingDeviceID:     deviceID,
		ChannelID:           channelID,
		SSRC:                ssrc,
		IsAudio:             isAudio,
		Fbody:               fbody,
	}
}

func DecodeSdpGetSSRC(sdpStr string) string {
	list := strings.Split(strings.ReplaceAll(sdpStr, "\r\n", "\n"), "\n")
	for _, e := range list {
		parts := strings.Split(e, "=")
		if len(parts) > 1 && strings.TrimSpace(parts[0]) == "y" {
			return parts[1]
		}
	}
	return ""
}

func DecodeSdpGetPushAddr(sdpStr string) (ip, port string) {
	list := strings.Split(strings.ReplaceAll(sdpStr, "\r\n", "\n"), "\n")
	for _, e := range list {
		parts := strings.Split(e, "=")
		if len(parts) > 1 && strings.TrimSpace(parts[0]) == "c" {
			//parts[1]=IN IP4 172.20.16.3
			partsChilds := strings.Split(parts[1], " ")
			if len(partsChilds) > 2 {
				ip = strings.TrimSpace(partsChilds[2])
			}
		}

		if len(parts) > 1 && strings.TrimSpace(parts[0]) == "m" {
			//parts[1]=audio 8000 RTP/AVP 8
			partsChilds := strings.Split(parts[1], " ")
			if len(partsChilds) > 2 {
				port = strings.TrimSpace(partsChilds[1])
			}
		}
	}

	return ip, port
}

func RandomString(n int) string {
	var letters = []rune("0123456789")
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	b := make([]rune, n)
	for i := range b {
		b[i] = letters[r.Intn(len(letters))]
	}

	return string(b)
}

type AudioInviteSubjectHeader struct {
	SourceDeviceID  string
	SourceDeviceTag string

	TargetDeviceID  string
	TargetDeviceTag string
}

func ParseSubjectHeaderFromAudioInvite(req *Request) (*AudioInviteSubjectHeader, error) {
	subjectHeaders := req.GetHeaders("Subject")
	if len(subjectHeaders) <= 0 {
		err := fmt.Errorf("len(subjectHeaders) <= 0")
		return nil, err
	}

	//Subject: 37010322021320001003:03d7a8ef3276a8ef327,37010322021320001002:0552354c54f3354c54f

	str := strings.Replace(subjectHeaders[0].String(), "Subject:", "", -1)
	str = strings.TrimSpace(str)

	devivceinfos := strings.Split(str, ",")
	if len(devivceinfos) != 2 {
		err := fmt.Errorf("len(devivceinfos) != 2, subjectHeaders[0].String()=%s", subjectHeaders[0].String())
		return nil, err
	}

	sourcedeviceinfos := strings.Split(devivceinfos[0], ":")
	targetdeviceinfos := strings.Split(devivceinfos[1], ":")

	if len(sourcedeviceinfos) != 2 {
		err := fmt.Errorf("len(sourcedeviceinfos) != 2, subjectHeaders[0].String()=%s", subjectHeaders[0].String())
		return nil, err
	}

	if len(targetdeviceinfos) != 2 {
		err := fmt.Errorf("len(targetdeviceinfos) != 2, subjectHeaders[0].String()=%s", subjectHeaders[0].String())
		return nil, err
	}

	return &AudioInviteSubjectHeader{
		SourceDeviceID:  sourcedeviceinfos[0],
		SourceDeviceTag: sourcedeviceinfos[1],
		TargetDeviceID:  targetdeviceinfos[0],
		TargetDeviceTag: targetdeviceinfos[1],
	}, nil
}
